/*
The SilverStripe ThemeMaker program is released under the Creative Commons non-commercial license
http://creativecommons.org/licenses/by-nc/3.0/us/
(http://creativecommons.org/licenses/by-nc/2.5/pl/ for poland)

author: Wojtek Szkutnik
http://silverstripe.pl
wojtek.szkutnik@gmail.com

The author does not take responsibility for any damage caused by the program.
*/

#include<cstring>
#include<iostream>
#include<vector>
#include<fstream>
#include<string>
#include<sstream>
#include<algorithm>

using namespace std;

// max length of the file extension permitted
const int max_allowed_extension_length = 7;

// switch the ASCIIArt messages on/off
const bool ASCIIArt = 1;

// structure - attribute of a tag
struct attrib {
       string name;
       string value;
};

// structure - a tag, itself
struct tag {
       // the parent in the tags tree       
       int parent;
       
       // the tag name
       string name;
       
       // children pointers vector [each entry is a vector<tag> tags id]
       vector<int> children;
       
       // attributes vector using the attrib structure
       vector<attrib> attributes;
       
       // is a self-closing tag?
       bool emptie;
       
       // is this a tag or just some text?
       bool plain_text;
};
 
// not used yet       
bool operator < (const attrib& a, const attrib& b){
     return a.name < b.name;
}

// the tags tree
vector<tag> tags;

// the output that is written to the file in case of saving
string output;

int point;

// the current level that the program is on
int level;

// this function runs through the tags tree
void inspect(int id) {
     // number of children
     int children = tags[id].children.size();
     
     // number of attributes
     int attribs = tags[id].attributes.size();
     
     // if the entry is not a tag, it is processed to avoid inserting newline signs, blank spaces, tabulators etc
     if(tags[id].plain_text){
            string ef = "";
            int p = 0;
            int size = tags[id].name.size();
            while(p != size){
                if(tags[id].name[p] == ' '){
                     ef += ' ';
                     while(tags[id].name[p+1] == ' ' && p != size-1)
                           p++;
                     }
                else if(tags[id].name[p] != '\n' && tags[id].name[p] != '\t'){
                     ef += tags[id].name[p];
                     }
                p++;
                }
             if(ef != " " && ef != ""){
                   for(int j=0;j<level;j++)
                           output += "  "; // adding indentation
                   output += ef + '\n';
                   }
             }
     // if the entry is a tag, it is displayed in the specified way
     else {
          for(int j=0;j<level;j++)
                  output += "  "; // adding indentation
          output += "<" + tags[id].name;
          
          // printing attributes
          for(int j=0;j<attribs;j++) 
                  output += " " + tags[id].attributes[j].name + "=\"" + tags[id].attributes[j].value + "\"";
                  
          if(tags[id].emptie) 
                  output += " />";
          else 
                  output += ">";
          output += "\n";
          
          // the recursion stuff - we're going one level deeper
          level++;
          for(int j=0;j<children;j++) 
                  inspect(tags[id].children[j]);          
          level--;
          
          // after processing all the children trees, the closing tag is displayed
          if(!tags[id].emptie){
                  for(int j=0;j<level;j++)
                          output += "  "; // adding indentation
                  output += "</" + tags[id].name + ">\n";
                  }
          }
     }  

void aart(string alpha){
     if(alpha == "logo"){
              if(ASCIIArt){
                          printf("\n\n");
                          printf(" _|_|_|_|_|  _|    _|  _|_|_|_|  _|      _|  _|_|_|_|\n");
                          printf("     _|      _|    _|  _|        _|_|  _|_|  _|\n");
                          printf("     _|      _|_|_|_|  _|_|_|    _|  _|  _|  _|_|_|\n");
                          printf("     _|      _|    _|  _|        _|      _|  _|\n");
                          printf("     _|      _|    _|  _|_|_|_|  _|      _|  _|_|_|_|\n");
                          printf("\n\n");
                          printf("   _|      _|    _|_|    _|    _|  _|_|_|_|  _|_|_|\n");
                          printf("   _|_|  _|_|  _|    _|  _|  _|    _|        _|    _|\n");
                          printf("   _|  _|  _|  _|_|_|_|  _|_|      _|_|_|    _|_|_|\n");
                          printf("   _|      _|  _|    _|  _|  _|    _|        _|    _|\n");
                          printf("   _|      _|  _|    _|  _|    _|  _|_|_|_|  _|    _|\n"); 
                          }
              else printf("\n\n Welcome to the Theme Maker\n");
              }
     else if(alpha == "bye"){
              if(ASCIIArt){
                           printf("\n\n");
                           printf(" _|_|_|    _|      _|  _|_|_|_|  _|  \n");
                           printf(" _|    _|    _|  _|    _|        _|  \n");
                           printf(" _|_|_|        _|      _|_|_|    _|  \n");
                           printf(" _|    _|      _|      _|            \n");
                           printf(" _|_|_|        _|      _|_|_|_|  _|  \n");
                           }
              else printf("\n\n Bye!\n");
              }
                  
}       
   
int main(){
    //clearing the screen ;)
    system("cls");
    aart("logo");
    printf("\n\n\nPlease enter the filename that you want to open. \n\nBefore proceeding, please ensure that the path and filename are correct\n\n");
    string file_path = "";
    string file_ext = "";
    char temp;
    bool error = 0;
    scanf("%c",&temp);
    scanf("%c",&temp);
    while(temp != '\n'){
               file_path += temp;
               scanf("%c",&temp);
    }
    int path_size = file_path.size();
    string string_temp;
    int int_temp = min( path_size ,max_allowed_extension_length+1);
    error = 0;
    for(int i=0;i<int_temp;i++){
            if(file_path[path_size-1-i] == '.') {
                   error=0;
                   break;
                   }
            file_ext = file_path[path_size-1-i] + file_ext;
            }
    
    // detecting the file extension and displaying the description
    string description;
    if(file_ext == "html" || file_ext == "htm")
                description = "HTML";
    else if(file_ext == "xhtml" || file_ext == "xhtm")
                description = "XHTML";
    else if(file_ext == "php" || file_ext == "php5" || file_ext == "php4" || file_ext == "php3" || file_ext == "ph5" || file_ext == "ph4" || file_ext == "ph3")
                description = "PHP";
    else description = "unknown";
    
    if(description == "unknown" || error)
                   printf("An error was encountered: unknown file extension: %s.\n",file_ext.c_str());
    else {
         printf("\n%s file extension recognised.Processing...",description.c_str());
         }
    
    file_path = "file.html";
    ifstream myFile ( file_path.c_str() );
    string File;
    if (myFile.is_open()){
       while(!myFile.eof()){
                  getline(myFile,string_temp);
                  File += string_temp;
                  }
       int current = 0;
       int size = File.size();
       int current_parent = -1;
       int pointer = 0;
       bool inside = 0;
       int how_deep = 0;
       bool name = 0;
       bool inside_attrib = 0;
       while(pointer != size){
                     if(File[pointer] == '<'){
                                      pointer++;
                                      // a tag begins
                                      if(File[pointer] == '/'){
                                                         // a closing tag
                                                         current = current_parent;
                                                         current_parent = tags[current].parent;
                                                         while(File[pointer] != '>') pointer++;
                                                         pointer++;
                                                         how_deep--;
                                                         }
                                      else {
                                           // an opening or self-closing tag
                                           tag temporary;
                                           temporary.name = "";
                                           temporary.emptie = 0;
                                           temporary.plain_text = 0;
                                           temporary.parent = current;
                                           while(File[pointer] != ' ' && File[pointer] != '>' && File[pointer] != '/'){
                                                               temporary.name += File[pointer];
                                                               pointer++;
                                                               }
                                           attrib temp2;
                                           temp2.name = "";
                                           temp2.value = "";
                                           name = 1;
                                           inside_attrib = 0;
                                           while(!((File[pointer] == '>' || File[pointer] == '/') && !inside_attrib)){
                                                               if(File[pointer] == '=' && !inside_attrib){
                                                                                name = !name;
                                                                                }
                                                               else {
                                                                    if(File[pointer] == '"'){
                                                                                     if(inside_attrib){
                                                                                                       if(temp2.name != "" && temp2.value != "")
                                                                                                       temporary.attributes.push_back(temp2);
                                                                                                       temp2.name = "";
                                                                                                       temp2.value = "";
                                                                                                       name = !name;
                                                                                                       }
                                                                                     inside_attrib = !inside_attrib;
                                                                                     }
                                                                    else {
                                                                         if(name && File[pointer] != ' '){
                                                                                 temp2.name += File[pointer];
                                                                                 }
                                                                         else if(inside_attrib){
                                                                              temp2.value += File[pointer];
                                                                              }
                                                                         }
                                                                    }
                                                               
                                                               pointer++;
                                                               }               
                                           if(File[pointer] == '/'){
                                                            temporary.emptie = 1;
                                                            pointer += 2;
                                                            }
                                           else if(File[pointer] == '>'){
                                                temporary.emptie = 0;
                                                pointer++;
                                                }
                                                tags.push_back(temporary);
                                                
                                                if(current_parent != -1){
                                                                  tags[current].children.push_back(tags.size()-1);
                                                                  }
                                                if(File[pointer-1] == '>' && File[pointer-2] != '/') {
                                                how_deep++;
                                                current_parent = current;
                                                current = tags.size() - 1;
                                                }
                                           }
                                      
                                      }
                     else {
                          tag temporary;
                          temporary.plain_text = 1;
                          while(File[pointer] != '<' && pointer != size){
                                              if(File[pointer] != '\n')
                                              temporary.name += File[pointer];
                                              pointer++;
                          }
                          tags.push_back(temporary);
                          tags[current].children.push_back(tags.size()-1);
                          }
                     
                     }
       printf("completed. \nWhat would you like to do now?\n");
       string Command;
       cin >> Command;
       while(Command != "quit"){
       
       // lettercase changes
       if(Command == "AttribLettercase"){
                  printf("\n\n====== Attributes cleanup ======\nPlease enter the attribute and the modification mode:\n\n");
                  string in_ext,in_mode;
                  cin >> in_ext >> in_mode;
                  int size = tags.size();
                  for(int i=0;i<size;i++){
                          int size2 = tags[i].attributes.size();
                          for(int j=0;j<size2;j++){
                                  if(in_mode == "firstUpperCase"){
                                             if(tags[i].attributes[j].value[0] >= 97 && tags[i].attributes[j].name == in_ext)
                                             tags[i].attributes[j].value[0] -= 32;
                                  }
                                  else if(in_mode == "firstLowerCase"){
                                             if(tags[i].attributes[j].value[0] < 97 && tags[i].attributes[j].name == in_ext)
                                             tags[i].attributes[j].value[0] += 32;
                                  }
                                  }
                          }
                  }
                  
       // saving
       else if(Command == "save"){
            printf("\n\n====== Saving ======\nPlease enter the file name:\n\n");
            string file;
            cin >> file;
            point = 0;
            output = "";
            level = 0;
            inspect(0);
            ofstream myfile3;
            myfile3.open (file.c_str());
            myfile3 << output;
            myfile3.close();
            printf("\n Done. ");
            }
       else {
            printf("Unknown command. Please try again. \n");
       }
       printf("What would you like to do now?\n");
       cin >> Command;
       }
       aart("bye");
       }
       else 
    printf("\n\nFile not found. The program will quit.\n\n");
    return 0;
    }
